package com.ruicar.afs.cloud.channel.grade.controller;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruicar.afs.cloud.channel.grade.ao.GradeModelAO;
import com.ruicar.afs.cloud.channel.grade.constant.Constants;
import com.ruicar.afs.cloud.channel.grade.dto.GradeModelInfoDTO;
import com.ruicar.afs.cloud.channel.grade.entity.GradeModelInfo;
import com.ruicar.afs.cloud.channel.grade.entity.GradeModelResult;
import com.ruicar.afs.cloud.channel.grade.service.GradeModelInfoService;
import com.ruicar.afs.cloud.channel.grade.service.GradeModelResultService;
import com.ruicar.afs.cloud.channel.grade.vo.GradeDataETVO;
import com.ruicar.afs.cloud.channel.grade.vo.GradeModelResultVO;
import com.ruicar.afs.cloud.channel.grade.vo.GradeResultReturnVO;
import com.ruicar.afs.cloud.common.core.query.QueryCondition;
import com.ruicar.afs.cloud.common.core.security.util.SecurityUtils;
import com.ruicar.afs.cloud.common.core.util.IResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/grade/gradeModel")
@Api(value = "grade", description = "评级模型controller")
public class GradeModelInfoController {
    private static final Logger logger = LoggerFactory.getLogger(GradeModelInfoController.class);
    @Autowired
    private GradeModelInfoService gradeModelInfoService;
    @Autowired
    private GradeModelResultService gradeModelResultService;
    @Autowired
    private GradeModelAO gradeModelAO;


    @PostMapping("/queryGradeModel")
    @ApiOperation(value = "分页获取评级模型,也可以查询有效状态的模型")
    public IResponse<IPage<GradeModelInfoDTO>> queryGradeModel(@RequestBody QueryCondition<GradeModelInfo> condition) {
        logger.info("queryGradeModel方法输入参数：---->" + JSONObject.toJSONString(condition));
        Page page = new Page(condition.getPageNumber(), condition.getPageSize());
        IPage<GradeModelInfo> resultPage = gradeModelInfoService.page(page, Wrappers.<GradeModelInfo>query().lambda()
                .eq((condition.getCondition() != null && StringUtils.isNotBlank(condition.getCondition().getModelType())), GradeModelInfo::getModelType, condition.getCondition() == null ?
                        "" : condition.getCondition().getModelType())
                .eq((condition.getCondition() != null && StringUtils.isNotBlank(condition.getCondition().getState())), GradeModelInfo::getState, condition.getCondition() == null ? "" :
                        condition.getCondition().getState())
                .orderByDesc(GradeModelInfo::getTimestamps));
        if (CollectionUtils.isNotEmpty(resultPage.getRecords())) {
            List<GradeModelInfoDTO> dtoList = new ArrayList<GradeModelInfoDTO>();
            for (GradeModelInfo modelInfo : resultPage.getRecords()) {
                dtoList.add(this.translateModel(modelInfo));
            }
            IPage<GradeModelInfoDTO> returnPage = new Page<GradeModelInfoDTO>();
            returnPage.setRecords(dtoList);
            returnPage.setCurrent(resultPage.getCurrent());
            returnPage.setTotal(resultPage.getTotal());
            returnPage.setPages(resultPage.getPages());
            returnPage.setSize(resultPage.getSize());
            return IResponse.success(returnPage);
        } else {
            return IResponse.success(resultPage);
        }
    }

    @PostMapping("/queryAllGradeModel")
    @ApiOperation(value = "查询全部有效评级模型")
    public IResponse<IPage<GradeModelInfoDTO>> queryAllGradeModel() {
        List<GradeModelInfo> list = gradeModelInfoService.list(Wrappers.<GradeModelInfo>query().lambda()
                .eq(GradeModelInfo::getState, Constants.VALID_FLAG_VALID_1)
                .orderByDesc(GradeModelInfo::getTimestamps));
        if (CollectionUtils.isNotEmpty(list)) {
            return IResponse.success("").setData(list);
        } else {
            return IResponse.success("").setData(new ArrayList<GradeModelInfo>());
        }
    }

    @RequestMapping(value = "/getGradeModelById", method = RequestMethod.POST)
    @ApiOperation(value = "根据Id查询评级模型,查看模型用")
    public IResponse<GradeModelInfoDTO> getGradeModelById(@RequestParam String id) {
        if (StringUtils.isBlank(id)) {
            return IResponse.fail("查询失败，id不能为空！");
        }
        List<GradeModelInfo> list = gradeModelInfoService.list(Wrappers.<GradeModelInfo>query().lambda().eq(GradeModelInfo::getId, id));
        if (list.size() == 1) {
            GradeModelInfo info = list.get(0);
            GradeModelInfoDTO dto = new GradeModelInfoDTO();
            BeanUtils.copyProperties(info, dto);
            String[] useages = info.getUseage().split(",");
            dto.setModelUsage(useages);
            return IResponse.success("查询成功").setData(dto);
        } else {
            return IResponse.fail("数据异常，查到多条记录，请联系管理员！");
        }
    }

    @RequestMapping(value = "/getGradeModelByModelTypeAndId", method = RequestMethod.POST)
    @ApiOperation(value = "根据Id和模型类型查询评级模型，进入配置模型页面用")
    public IResponse<GradeModelInfo> getGradeModelByModelTypeAndId(@RequestParam String id, @RequestParam String modelType) {
        if (StringUtils.isBlank(id)) {
            return IResponse.fail("查询失败，id不能为空！");
        }
        if (StringUtils.isBlank(modelType)) {
            return IResponse.fail("查询失败，模型类型不能为空！");
        }
        logger.info("getGradeModelByModelTypeAndId方法输入参数：---->id=" + id + ",modelType=" + modelType);
        List<GradeModelInfo> list = gradeModelInfoService.list(Wrappers.<GradeModelInfo>query().lambda().eq(GradeModelInfo::getId, id).eq(GradeModelInfo::getModelType, modelType));
        if (list.size() == 1) {
            return IResponse.success("查询成功").setData(list.get(0));
        } else {
            return IResponse.fail("数据异常，查到多条记录，请联系管理员！");
        }
    }

    @Transactional
    @PostMapping("/save")
    @ApiOperation(value = "保存评级模型")
    public IResponse<Boolean> save(@RequestBody GradeModelInfoDTO gradeModelInfoDTO) throws Exception {
        if (gradeModelInfoDTO == null) {
            return IResponse.fail("参数不能为空，请联系管理员！");
        }
        if (gradeModelInfoDTO.getId() != null) {
            return IResponse.fail("参数id不为空，请联系管理员！");
        }
        logger.info("save方法输入参数：---->" + JSONObject.toJSONString(gradeModelInfoDTO));
        if (StringUtils.isNotEmpty(gradeModelInfoDTO.getModelCode())) {
            if (gradeModelInfoDTO.getModelCode().trim().length() > 6) {
                return IResponse.fail("模型代码长度不能超过6位！");
            }
        } else {
            return IResponse.fail("参数模型代码不能为空，请联系管理员！");
        }
        try {
            //判断模型代码是否已存在
            List<GradeModelInfo> gradeModelInfos = gradeModelInfoService.list(Wrappers.<GradeModelInfo>query().lambda()
                    .eq(GradeModelInfo::getModelCode, gradeModelInfoDTO.getModelCode()));
            if (CollectionUtils.isNotEmpty(gradeModelInfos)) {
                return IResponse.fail("不能新增，模型代码" + gradeModelInfoDTO.getModelCode() + "已存在，请联系管理员！");
            }
            //若新增的模型3要素相同并且其中的状态为生效（生效的模型只能有一个）
            if (Constants.VALID_FLAG_VALID_1.equals(gradeModelInfoDTO.getState())) {
                List<GradeModelInfo> list = gradeModelInfoService.list(Wrappers.<GradeModelInfo>query().lambda()
                        .eq(GradeModelInfo::getState, gradeModelInfoDTO.getState())
                        .eq(GradeModelInfo::getModelType, gradeModelInfoDTO.getModelType())
                        .eq(GradeModelInfo::getTimeDimension, gradeModelInfoDTO.getTimeDimension()));
                if (CollectionUtils.isNotEmpty(list)) {
                    return IResponse.fail("已存在同类型、同时间维度并生效的模型，请联系管理员！");
                } else {
                    //有效状态3要素模型size=0，直接保存
                    gradeModelInfoService.save(this.translateDTO(gradeModelInfoDTO));
                    return IResponse.success("保存成功");
                }
            } else {
                //新增的模型是无效状态直接保存
                gradeModelInfoService.save(this.translateDTO(gradeModelInfoDTO));
                return IResponse.success("保存成功");
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            //手动开启事务回滚
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return IResponse.fail("保存失败，请联系管理员！");
        }
    }

    /**
     * @Description: 将gradeModelInfoDTO转换为gradeModelInfo
     * @param: [gradeModelInfoDTO, gradeModelInfo]
     * @return: com.ruicar.afs.cloud.channel.grade.entity.GradeModelInfo
     * @auther: jiangxiongfei
     * @date: 2020-09-14 20:22
     */
    private GradeModelInfoDTO translateModel(GradeModelInfo gradeModelInfo) throws IllegalStateException {
        GradeModelInfoDTO modelInfoDTO = new GradeModelInfoDTO();
        BeanUtils.copyProperties(gradeModelInfo, modelInfoDTO);
        if (gradeModelInfo.getUseage() != null) {
            String[] array = gradeModelInfo.getUseage().split(",");
            if (array != null && array.length > 0) {
                modelInfoDTO.setModelUsage(array);
            }
        }
        return modelInfoDTO;
    }

    /**
     * @Description: 将gradeModelInfoDTO转换为gradeModelInfo
     * @param: [gradeModelInfoDTO, gradeModelInfo]
     * @return: com.ruicar.afs.cloud.channel.grade.entity.GradeModelInfo
     * @auther: jiangxiongfei
     * @date: 2020-09-14 20:22
     */
    private GradeModelInfo translateDTO(GradeModelInfoDTO gradeModelInfoDTO) throws IllegalStateException {
        GradeModelInfo modelInfo = new GradeModelInfo();
        BeanUtils.copyProperties(gradeModelInfoDTO, modelInfo);
        String useages = "";
        String[] array = gradeModelInfoDTO.getModelUsage();
        if (array != null && array.length > 0) {
            for (int i = 0; i < array.length; i++) {
                useages += array[i] + ",";
            }
        }
        useages = StringUtils.isNotBlank(useages) ? useages.substring(0, useages.length() - 1) : "";
        modelInfo.setUseage(useages);
        modelInfo.setTimestamps(new Date());
        modelInfo.setLastUpdDate(new Date());
        return modelInfo;
    }

    @Transactional
    @PostMapping("/edit")
    @ApiOperation(value = "修改评级模型")
    public IResponse<Boolean> edit(@RequestBody GradeModelInfoDTO gradeModelInfoDTO) throws Exception {
        if (gradeModelInfoDTO == null) {
            return IResponse.fail("参数不能为空，请联系管理员！");
        }
        if (gradeModelInfoDTO.getId() == null) {
            return IResponse.fail("参数id不能为空，请联系管理员！");
        }
        logger.info("输入参数：---->" + JSONObject.toJSONString(gradeModelInfoDTO));
        if (StringUtils.isNotEmpty(gradeModelInfoDTO.getModelCode())) {
            if (gradeModelInfoDTO.getModelCode().trim().length() > 6) {
                return IResponse.fail("模型代码长度不能超过6位！");
            }
        } else {
            return IResponse.fail("参数模型代码不能为空，请联系管理员！");
        }
        try {
            GradeModelInfo modelInfo = gradeModelInfoService.getOne(Wrappers.<GradeModelInfo>query().lambda()
                    .eq(GradeModelInfo::getId, gradeModelInfoDTO.getId()));
            if (modelInfo != null) {
                if (modelInfo.getModelCode() != null) {
                    if (!modelInfo.getModelCode().equals(gradeModelInfoDTO.getModelCode())) {
                        //判断模型代码是否已存在
                        List<GradeModelInfo> list = gradeModelInfoService.list(Wrappers.<GradeModelInfo>query().lambda()
                                .eq(GradeModelInfo::getModelCode, gradeModelInfoDTO.getModelCode()));
                        if (CollectionUtils.isNotEmpty(list)) {
                            return IResponse.fail("不能修改，模型代码" + gradeModelInfoDTO.getModelCode() + "已存在，请联系管理员！");
                        }
                    }
                } else {
                    return IResponse.fail("数据异常，保存的模型代码为空，请联系管理员！");
                }
            } else {
                return IResponse.fail("数据不存在，请联系管理员！");
            }

            List<GradeModelInfo> gradeModelInfos = gradeModelInfoService.list(Wrappers.<GradeModelInfo>query().lambda()
                    .eq(GradeModelInfo::getState, gradeModelInfoDTO.getState())
                    .eq(GradeModelInfo::getModelType, gradeModelInfoDTO.getModelType())
                    .eq(GradeModelInfo::getTimeDimension, gradeModelInfoDTO.getTimeDimension()));
            //若三要素都相同的情况存在
            if (CollectionUtils.isNotEmpty(gradeModelInfos)) {
                if (Constants.VALID_FLAG_VALID_1.equals(gradeModelInfoDTO.getState())) {
                    //若有效状态记录非空
                    if (gradeModelInfos.size() == 1) {
                        //若查询到的记录就是当前记录,保存
                        if (gradeModelInfos.get(0).getId().longValue() == gradeModelInfoDTO.getId().longValue()) {
                            gradeModelInfoService.saveOrUpdate(this.translate(gradeModelInfoDTO, modelInfo));
                            return IResponse.success("保存成功");
                        } else {
                            //若查询到的记录不是当前记录,提示不能修改
                            return IResponse.fail("不能修改，已存在有效状态记录，请联系管理员！");
                        }
                    } else { //size>1的请求，数据异常
                        return IResponse.fail("数据异常，存在多条有效记录，请联系管理员！");
                    }
                } else {
                    //若无效状态记录非空，直接保存
                    gradeModelInfoService.saveOrUpdate(this.translate(gradeModelInfoDTO, modelInfo));
                    return IResponse.success("保存成功");
                }
            } else {
                //size=0,若三要素都相同的情况不存在，直接保存
                gradeModelInfoService.saveOrUpdate(this.translate(gradeModelInfoDTO, modelInfo));
                return IResponse.success("保存成功");
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            //手动开启事务回滚
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return IResponse.fail("保存失败，请联系管理员！");
        }
    }

    /**
     * @Description: 将gradeModelInfoDTO转换为gradeModelInfo
     * @param: [gradeModelInfoDTO, gradeModelInfo]
     * @return: com.ruicar.afs.cloud.channel.grade.entity.GradeModelInfo
     * @auther: jiangxiongfei
     * @date: 2020-09-14 20:22
     */
    private GradeModelInfo translate(GradeModelInfoDTO gradeModelInfoDTO, GradeModelInfo gradeModelInfo) throws IllegalStateException {
        String useages = "";
        String[] array = gradeModelInfoDTO.getModelUsage();
        if (array != null && array.length > 0) {
            for (int i = 0; i < array.length; i++) {
                useages += array[i] + ",";
            }
        }
        useages = StringUtils.isNotBlank(useages) ? useages.substring(0, useages.length() - 1) : "";
        gradeModelInfo.setUseage(useages);
        gradeModelInfo.setModelCode(gradeModelInfoDTO.getModelCode());
        gradeModelInfo.setModelName(gradeModelInfoDTO.getModelName());
        gradeModelInfo.setModelScore(gradeModelInfoDTO.getModelScore());
        gradeModelInfo.setModelType(gradeModelInfoDTO.getModelType());
        gradeModelInfo.setModelValue(gradeModelInfoDTO.getModelValue());
        gradeModelInfo.setState(gradeModelInfoDTO.getState());
        gradeModelInfo.setRemark(gradeModelInfoDTO.getRemark());
        gradeModelInfo.setTimeDimension(gradeModelInfoDTO.getTimeDimension());
        gradeModelInfo.setLastUpdDate(new Date());
        return gradeModelInfo;
    }

    @Transactional
    @PostMapping("/delete")
    @ApiOperation(value = "删除评级模型")
    public IResponse<Boolean> delete(@RequestParam String id) throws Exception {
        if (StringUtils.isBlank(id)) {
            return IResponse.fail("查询失败，id不能为空！");
        }
        List<GradeModelInfo> list = gradeModelInfoService.list(Wrappers.<GradeModelInfo>query().lambda().eq(GradeModelInfo::getId, id));
        if (list != null && list.size() == 1) {
            try {
                gradeModelInfoService.removeById(id);
                return IResponse.success("删除成功");
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                //手动开启事务回滚
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return IResponse.fail("删除失败，请联系管理员！");
            }
        } else if (list != null && list.size() > 1) {
            return IResponse.fail("数据异常，查到多条记录，请联系管理员！");
        } else {
            return IResponse.fail("数据不存在");
        }
    }

    @Transactional
    @PostMapping("/calc")
    @ApiOperation(value = "根据模型计算")
    public IResponse<GradeResultReturnVO> calc(@RequestBody GradeModelResultVO gradeModelResultVO) throws Exception {
        if (gradeModelResultVO == null) {
            return IResponse.fail("计算失败，参数不能为空！");
        }
        logger.info("calc方法输入参数：---->" + JSONObject.toJSONString(gradeModelResultVO));
        if (CollectionUtils.isEmpty(gradeModelResultVO.getGradeInfoMap())) {
            return IResponse.fail("指标参数不能为空，请联系管理员！");
        }
        try {
            //调用评分方法
            GradeResultReturnVO gradeResultReturnVO = new GradeResultReturnVO();
            BeanUtils.copyProperties(gradeModelResultVO, gradeResultReturnVO);
            Map gradeInfoMap = new HashedMap(); //用来装指标以及指标值
            List<Map<String, String>> mapList = gradeModelResultVO.getGradeInfoMap();//传过来的指标和实际指标选项值参数
            for (Map<String, String> map : mapList) {
                for (Map.Entry<String, String> vo : map.entrySet()) {
                    GradeDataETVO gradeDataETVO = new GradeDataETVO();
                    gradeDataETVO.setKey(vo.getKey());
                    gradeDataETVO.setCode(vo.getKey());
                    gradeDataETVO.setValue(vo.getValue());
                    gradeInfoMap.put(vo.getKey(), gradeDataETVO);
                }
            }
            gradeResultReturnVO = gradeModelAO.handleModelRecordResult(SecurityUtils.getUser().getDeptId(), SecurityUtils.getUser().getId(), gradeInfoMap,
                    gradeModelResultVO.getModelCode(), "0", gradeResultReturnVO, null, "1", null);
            //根据得分获取信用等级
            String grade = gradeModelAO.getGradeByScore(gradeResultReturnVO.getScore());
            /*******************************限定条件处理 begin *******************************/
/*            String finalGrade = grade;
            String maxGrade = "";
            String remark = "";
            //主评级的才处理限定条件
            if ("1".equals(gradeModelResultVO.getModelType()) && (gradeModelResultVO.getModelCode().startsWith("1") || gradeModelResultVO.getModelCode().startsWith("4"))) {//一般企业和房地产
                //1.1、测评年度资产负债率大于70%,信用等级原则上不得超过AA级
                BigDecimal dsRatio = getDsRatio(gradeModelResultVO.getCustcd(), gradeModelResultVO.getTerm());
                if (dsRatio.compareTo(new BigDecimal(70)) == 1) {
                    maxGrade = Constants.GRADE_LEVEL_AA;
                    if (finalGrade.compareTo(maxGrade) == -1) {
                        finalGrade = maxGrade;
                        remark = "测评年度资产负债率大于70%,信用等级由【" + gradeName + "】调整为【AA】。";
                    }
                }
                //1.2、测评年度资产负债率大于75%,信用等级原则上不得超过A级
                if (dsRatio.compareTo(new BigDecimal(75)) == 1) {
                    maxGrade = Constants.GRADE_LEVEL_A;
                    if (finalGrade.compareTo(maxGrade) == -1) {
                        finalGrade = maxGrade;
                        remark = "测评年度资产负债率大于75%,信用等级由【" + gradeName + "】调整为【A】。";
                    }
                }
                //2.1、测评年度亏损(净利润<0),信用等级原则上不得超过A级
                BigDecimal netProfit = getNetProfit(gradeModelResultVO.getCustcd(), gradeModelResultVO.getTerm());
                if (netProfit.compareTo(new BigDecimal(0)) == -1) {
                    maxGrade = Constants.GRADE_LEVEL_A;
                    if (finalGrade.compareTo(maxGrade) == -1) {
                        finalGrade = maxGrade;
                        remark = "测评年度亏损,信用等级由【" + gradeName + "】调整为【A】。";
                    }
                }
                //2.2、测评年度和最近一期均亏损,信用等级原则上不得超过BBB级
                String lastTerm = getLastTerm(gradeModelResultVO.getCustcd());
                BigDecimal lastNetProfit = getNetProfit(gradeModelResultVO.getCustcd(), lastTerm);
                if (netProfit.compareTo(new BigDecimal(0)) == -1 && lastNetProfit.compareTo(new BigDecimal(0)) == -1) {
                    maxGrade = Constants.GRADE_LEVEL_BBB;
                    if (finalGrade.compareTo(maxGrade) == -1) {
                        finalGrade = maxGrade;
                        remark = "测评年度和最近一期均亏损,信用等级由【" + gradeName + "】调整为【BBB】。";
                    }
                }

                //5.1、最新一期五级分类存在次级类资产,信用等级原则上不得超过A级
                String fiveClass = getFiveClass(gradeModelResultVO.getCustcd());
                if (fiveClass.compareTo(Constants.CLR_CLASS_LESSER) > -1) {
                    maxGrade = Constants.GRADE_LEVEL_A;
                    if (finalGrade.compareTo(maxGrade) == -1) {
                        finalGrade = maxGrade;
                        remark = "最新一期五级分类存在次级类资产,信用等级由【" + gradeName + "】调整为【A】。";
                    }
                }

                //5.2、最新一期五级分类存在可疑类资产,信用等级原则上不得超过BBB级
                if (fiveClass.compareTo(Constants.CLR_CLASS_SHADINESS) > -1) {
                    maxGrade = Constants.GRADE_LEVEL_BBB;
                    if (finalGrade.compareTo(maxGrade) == -1) {
                        finalGrade = maxGrade;
                        remark = "最新一期五级分类存在次级类资产,信用等级由【" + gradeName + "】调整为【BBB】。";
                    }
                }
            }*/
            /*******************************限定条件处理 end *********************************/

            //更新等级到评分结果表
            GradeModelResult gradeModelResult = gradeModelResultService.getOne(Wrappers.<GradeModelResult>query().lambda().eq(GradeModelResult::getId, gradeResultReturnVO.getId()));
            // gradeModelResult.setModelValue(finalGrade);
            // gradeModelResult.setRemark(remark);
            gradeModelResult.setModelValue(grade);
            gradeModelResult.setRemark("");
            gradeModelResultService.saveOrUpdate(gradeModelResult);

            return IResponse.success("计算成功").setData(gradeResultReturnVO);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            //手动开启事务回滚
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return IResponse.fail("计算失败，请联系管理员！");
        }
    }


}
